import { HttpException, HttpStatus, Logger } from '@nestjs/common'

/**
 * 标准化异常响应接口
 */
export interface StandardErrorResponse {
  statusCode: number
  message: string
  error: string
  timestamp: string
  path?: string
  details?: any
}

/**
 * 异常工具类
 * 统一处理项目中的异常和错误响应
 */
export class ExceptionUtil {
  private static readonly logger = new Logger(ExceptionUtil.name)

  /**
   * 创建标准化的HTTP异常
   * @param message 错误消息
   * @param status HTTP状态码
   * @param details 详细信息
   * @returns HttpException
   */
  static createHttpException(
    message: string,
    status: HttpStatus = HttpStatus.BAD_REQUEST,
    details?: any
  ): HttpException {
    const errorResponse: StandardErrorResponse = {
      statusCode: status,
      message,
      error: HttpStatus[status],
      timestamp: new Date().toISOString(),
      ...(details && { details })
    }

    return new HttpException(errorResponse, status)
  }

  /**
   * 处理数据库错误
   * @param error 原始错误
   * @param context 上下文信息
   * @returns HttpException
   */
  static handleDatabaseError(error: any, context?: string): HttpException {
    this.logger.error(`数据库错误 ${context ? `[${context}]` : ''}: ${error.message}`, error.stack)

    // Prisma 错误处理
    if (error.code) {
      switch (error.code) {
        case 'P2002':
          return this.createHttpException('数据已存在，违反唯一性约束', HttpStatus.CONFLICT)
        case 'P2025':
          return this.createHttpException('记录不存在', HttpStatus.NOT_FOUND)
        case 'P2003':
          return this.createHttpException('外键约束失败', HttpStatus.BAD_REQUEST)
        case 'P2014':
          return this.createHttpException('关联记录不存在', HttpStatus.BAD_REQUEST)
        default:
          return this.createHttpException('数据库操作失败', HttpStatus.INTERNAL_SERVER_ERROR)
      }
    }

    return this.createHttpException('数据库操作失败', HttpStatus.INTERNAL_SERVER_ERROR)
  }

  /**
   * 处理验证错误
   * @param errors 验证错误数组
   * @returns HttpException
   */
  static handleValidationError(errors: any[]): HttpException {
    const messages = errors.map(error => {
      if (error.constraints) {
        return Object.values(error.constraints).join(', ')
      }
      return error.message || '验证失败'
    })

    return this.createHttpException('输入数据验证失败', HttpStatus.BAD_REQUEST, { validationErrors: messages })
  }

  /**
   * 处理认证错误
   * @param message 错误消息
   * @param context 上下文
   * @returns HttpException
   */
  static handleAuthError(message: string = '认证失败', context?: string): HttpException {
    this.logger.warn(`认证错误 ${context ? `[${context}]` : ''}: ${message}`)
    return this.createHttpException(message, HttpStatus.UNAUTHORIZED)
  }

  /**
   * 处理权限错误
   * @param message 错误消息
   * @param context 上下文
   * @returns HttpException
   */
  static handlePermissionError(message: string = '权限不足', context?: string): HttpException {
    this.logger.warn(`权限错误 ${context ? `[${context}]` : ''}: ${message}`)
    return this.createHttpException(message, HttpStatus.FORBIDDEN)
  }

  /**
   * 处理文件操作错误
   * @param error 原始错误
   * @param context 上下文
   * @returns HttpException
   */
  static handleFileError(error: any, context?: string): HttpException {
    this.logger.error(`文件操作错误 ${context ? `[${context}]` : ''}: ${error.message}`, error.stack)

    if (error.code === 'ENOENT') {
      return this.createHttpException('文件不存在', HttpStatus.NOT_FOUND)
    }
    if (error.code === 'EACCES') {
      return this.createHttpException('文件访问权限不足', HttpStatus.FORBIDDEN)
    }
    if (error.code === 'ENOSPC') {
      return this.createHttpException('磁盘空间不足', HttpStatus.INSUFFICIENT_STORAGE)
    }

    return this.createHttpException('文件操作失败', HttpStatus.INTERNAL_SERVER_ERROR)
  }

  /**
   * 处理网络错误
   * @param error 原始错误
   * @param context 上下文
   * @returns HttpException
   */
  static handleNetworkError(error: any, context?: string): HttpException {
    this.logger.error(`网络错误 ${context ? `[${context}]` : ''}: ${error.message}`, error.stack)

    if (error.code === 'ECONNREFUSED') {
      return this.createHttpException('连接被拒绝', HttpStatus.SERVICE_UNAVAILABLE)
    }
    if (error.code === 'ETIMEDOUT') {
      return this.createHttpException('连接超时', HttpStatus.REQUEST_TIMEOUT)
    }

    return this.createHttpException('网络请求失败', HttpStatus.BAD_GATEWAY)
  }

  /**
   * 记录并抛出通用错误
   * @param error 原始错误
   * @param context 上下文
   * @param message 自定义消息
   * @returns HttpException
   */
  static logAndThrow(error: any, context?: string, message: string = '操作失败'): HttpException {
    this.logger.error(`${message} ${context ? `[${context}]` : ''}: ${error.message}`, error.stack)

    // 如果已经是HttpException，直接抛出
    if (error instanceof HttpException) {
      return error
    }

    return this.createHttpException(message, HttpStatus.INTERNAL_SERVER_ERROR)
  }
}
